const axios = require('axios');
const config = require('../../config/config');
const { setupLogger } = require('../../utils/logger');

class CoinGeckoService {
  constructor() {
    this.logger = setupLogger();
    this.baseUrl = config.dataSources.coinGecko.baseUrl;
    this.apiKey = config.dataSources.coinGecko.apiKey;
    this.rateLimitRemaining = 50;
    this.rateLimitReset = Date.now();
  }

  async fetchData() {
    try {
      this.logger.info('开始获取CoinGecko数据...');
      
      // 检查速率限制
      if (this.rateLimitRemaining <= 0 && Date.now() < this.rateLimitReset) {
        this.logger.warn('CoinGecko API速率限制，跳过本次获取');
        return [];
      }

      const data = [];
      
      // 获取市场数据
      const marketData = await this.getCoinsMarkets();
      data.push(...marketData);
      
      // 获取热门币种
      const trendingCoins = await this.getTrendingCoins();
      data.push(...trendingCoins);
      
      // 获取全球市场数据
      const globalData = await this.getGlobalData();
      if (globalData) data.push(globalData);
      
      // 获取交易所信息
      const exchanges = await this.getExchanges();
      data.push(...exchanges);
      
      // 获取DeFi数据
      const defiData = await this.getDefiData();
      if (defiData) data.push(defiData);
      
      // 获取NFT数据
      const nftData = await this.getNftData();
      data.push(...nftData);
      
      this.logger.info(`CoinGecko数据获取完成，共获取 ${data.length} 条数据`);
      return data;
    } catch (error) {
      this.logger.error('CoinGecko数据获取失败:', error);
      return [];
    }
  }

  async getCoinsMarkets() {
    try {
      const params = {
        vs_currency: 'usd',
        order: 'market_cap_desc',
        per_page: 100,
        page: 1,
        sparkline: false,
        price_change_percentage: '1h,24h,7d'
      };

      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/coins/markets`, { params });
      
      this.updateRateLimit(response.headers);
      
      return response.data.map(coin => ({
        source: 'coingecko',
        type: 'market_data',
        id: coin.id,
        symbol: coin.symbol,
        name: coin.name,
        image: coin.image,
        currentPrice: coin.current_price,
        marketCap: coin.market_cap,
        marketCapRank: coin.market_cap_rank,
        fullyDilutedValuation: coin.fully_diluted_valuation,
        totalVolume: coin.total_volume,
        high24h: coin.high_24h,
        low24h: coin.low_24h,
        priceChange24h: coin.price_change_24h,
        priceChangePercentage24h: coin.price_change_percentage_24h,
        priceChangePercentage1h: coin.price_change_percentage_1h_in_currency,
        priceChangePercentage7d: coin.price_change_percentage_7d_in_currency,
        marketCapChange24h: coin.market_cap_change_24h,
        marketCapChangePercentage24h: coin.market_cap_change_percentage_24h,
        circulatingSupply: coin.circulating_supply,
        totalSupply: coin.total_supply,
        maxSupply: coin.max_supply,
        ath: coin.ath,
        athChangePercentage: coin.ath_change_percentage,
        athDate: coin.ath_date,
        atl: coin.atl,
        atlChangePercentage: coin.atl_change_percentage,
        atlDate: coin.atl_date,
        lastUpdated: coin.last_updated,
        timestamp: new Date().toISOString()
      }));
    } catch (error) {
      this.logger.error('获取CoinGecko市场数据失败:', error);
      return [];
    }
  }

  async getTrendingCoins() {
    try {
      const params = {};
      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/search/trending`, { params });
      
      this.updateRateLimit(response.headers);
      
      const data = [];
      
      // 热门币种
      if (response.data.coins) {
        response.data.coins.forEach(item => {
          data.push({
            source: 'coingecko',
            type: 'trending_coin',
            id: item.item.id,
            coinId: item.item.coin_id,
            name: item.item.name,
            symbol: item.item.symbol,
            marketCapRank: item.item.market_cap_rank,
            thumb: item.item.thumb,
            small: item.item.small,
            large: item.item.large,
            slug: item.item.slug,
            priceBtc: item.item.price_btc,
            score: item.item.score,
            timestamp: new Date().toISOString()
          });
        });
      }
      
      // 热门NFT
      if (response.data.nfts) {
        response.data.nfts.forEach(item => {
          data.push({
            source: 'coingecko',
            type: 'trending_nft',
            id: item.id,
            name: item.name,
            symbol: item.symbol,
            thumb: item.thumb,
            nftContractId: item.nft_contract_id,
            nativeCurrencySymbol: item.native_currency_symbol,
            floorPriceInNativeCurrency: item.floor_price_in_native_currency,
            floorPrice24hPercentageChange: item.floor_price_24h_percentage_change,
            timestamp: new Date().toISOString()
          });
        });
      }
      
      return data;
    } catch (error) {
      this.logger.error('获取CoinGecko热门数据失败:', error);
      return [];
    }
  }

  async getGlobalData() {
    try {
      const params = {};
      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/global`, { params });
      
      this.updateRateLimit(response.headers);
      
      const global = response.data.data;
      return {
        source: 'coingecko',
        type: 'global_data',
        activeCryptocurrencies: global.active_cryptocurrencies,
        upcomingIcos: global.upcoming_icos,
        ongoingIcos: global.ongoing_icos,
        endedIcos: global.ended_icos,
        markets: global.markets,
        totalMarketCap: global.total_market_cap,
        totalVolume: global.total_volume,
        marketCapPercentage: global.market_cap_percentage,
        marketCapChangePercentage24hUsd: global.market_cap_change_percentage_24h_usd,
        updatedAt: global.updated_at,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      this.logger.error('获取CoinGecko全球数据失败:', error);
      return null;
    }
  }

  async getExchanges() {
    try {
      const params = {
        per_page: 20,
        page: 1
      };
      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/exchanges`, { params });
      
      this.updateRateLimit(response.headers);
      
      return response.data.map(exchange => ({
        source: 'coingecko',
        type: 'exchange',
        id: exchange.id,
        name: exchange.name,
        yearEstablished: exchange.year_established,
        country: exchange.country,
        description: exchange.description,
        url: exchange.url,
        image: exchange.image,
        hasTradingIncentive: exchange.has_trading_incentive,
        trustScore: exchange.trust_score,
        trustScoreRank: exchange.trust_score_rank,
        tradeVolume24hBtc: exchange.trade_volume_24h_btc,
        tradeVolume24hBtcNormalized: exchange.trade_volume_24h_btc_normalized,
        timestamp: new Date().toISOString()
      }));
    } catch (error) {
      this.logger.error('获取CoinGecko交易所数据失败:', error);
      return [];
    }
  }

  async getDefiData() {
    try {
      const params = {};
      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/global/decentralized_finance_defi`, { params });
      
      this.updateRateLimit(response.headers);
      
      const defi = response.data.data;
      return {
        source: 'coingecko',
        type: 'defi_data',
        defiMarketCap: defi.defi_market_cap,
        ethMarketCap: defi.eth_market_cap,
        defiToEthRatio: defi.defi_to_eth_ratio,
        tradingVolume24h: defi.trading_volume_24h,
        defiDominance: defi.defi_dominance,
        topCoinName: defi.top_coin_name,
        topCoinDefiDominance: defi.top_coin_defi_dominance,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      this.logger.error('获取CoinGecko DeFi数据失败:', error);
      return null;
    }
  }

  async getNftData() {
    try {
      const params = {
        order: 'market_cap_usd_desc',
        per_page: 20,
        page: 1
      };
      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/nfts/list`, { params });
      
      this.updateRateLimit(response.headers);
      
      return response.data.map(nft => ({
        source: 'coingecko',
        type: 'nft_data',
        id: nft.id,
        contractAddress: nft.contract_address,
        name: nft.name,
        assetPlatformId: nft.asset_platform_id,
        symbol: nft.symbol,
        image: nft.image,
        description: nft.description,
        nativeCurrency: nft.native_currency,
        floorPrice: nft.floor_price,
        marketCap: nft.market_cap,
        volume24h: nft.volume_24h,
        floorPriceInUsd24hPercentageChange: nft.floor_price_in_usd_24h_percentage_change,
        floorPrice24hPercentageChange: nft.floor_price_24h_percentage_change,
        marketCap24hPercentageChange: nft.market_cap_24h_percentage_change,
        volume24hPercentageChange: nft.volume_24h_percentage_change,
        numberOfUniqueAddresses: nft.number_of_unique_addresses,
        numberOfUniqueAddresses24hPercentageChange: nft.number_of_unique_addresses_24h_percentage_change,
        totalSupply: nft.total_supply,
        timestamp: new Date().toISOString()
      }));
    } catch (error) {
      this.logger.error('获取CoinGecko NFT数据失败:', error);
      return [];
    }
  }

  async getCoinData(coinId) {
    try {
      const params = {
        localization: false,
        tickers: false,
        market_data: true,
        community_data: true,
        developer_data: true,
        sparkline: false
      };
      if (this.apiKey) {
        params.x_cg_demo_api_key = this.apiKey;
      }

      const response = await axios.get(`${this.baseUrl}/coins/${coinId}`, { params });
      
      this.updateRateLimit(response.headers);
      
      const coin = response.data;
      return {
        source: 'coingecko',
        type: 'coin_detail',
        id: coin.id,
        symbol: coin.symbol,
        name: coin.name,
        description: coin.description?.en,
        image: coin.image,
        marketCapRank: coin.market_cap_rank,
        coingeckoRank: coin.coingecko_rank,
        coingeckoScore: coin.coingecko_score,
        developerScore: coin.developer_score,
        communityScore: coin.community_score,
        liquidityScore: coin.liquidity_score,
        publicInterestScore: coin.public_interest_score,
        marketData: coin.market_data,
        communityData: coin.community_data,
        developerData: coin.developer_data,
        publicInterestStats: coin.public_interest_stats,
        lastUpdated: coin.last_updated,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      this.logger.error(`获取币种详情失败 ${coinId}:`, error);
      return null;
    }
  }

  updateRateLimit(headers) {
    // CoinGecko免费API限制为50次/分钟
    this.rateLimitRemaining = Math.max(0, this.rateLimitRemaining - 1);
    if (this.rateLimitRemaining === 0) {
      this.rateLimitReset = Date.now() + 60 * 1000; // 1分钟后重置
    }
  }

  delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  }

  getRateLimitStatus() {
    return {
      remaining: this.rateLimitRemaining,
      resetTime: new Date(this.rateLimitReset).toISOString()
    };
  }
}

module.exports = new CoinGeckoService();

